<template>
  <div class="main">
    <!-- 文件上传按钮 -->
    <el-upload action="#" :http-request="upload" :before-upload="beforeUpload" :show-file-list="false" drag>
      <el-button type="primary">选择上传文件</el-button>
    </el-upload>

    <el-divider content-position="left">上传列表</el-divider>
    <!-- 正在上传的文件列表 -->
    <div class="uploading" v-for="uploadFile in uploadFileList">
      <span class="fileName">{{ uploadFile.name }}</span>
      <span class="fileSize">{{ formatSize(uploadFile.size) }}</span>

      <div class="parse">
        <span>解析进度： </span>
        <el-progress :text-inside="true" :stroke-width="16" :percentage="uploadFile.parsePercentage" />
      </div>

      <div class="progress">
        <span>上传进度：</span>
        <el-progress :text-inside="true" :stroke-width="16" :percentage="uploadFile.uploadPercentage" />
        <span class="uploadSpeed">{{ uploadFile.uploadSpeed }}</span>
        <span v-if="(uploadFile.uploadPercentage > 0) & (uploadFile.uploadPercentage < 100)">
          <el-button circle @click="changeUploadingStop(uploadFile)">
            <i class="el-icon-video-pause" v-if="uploadFile.uploadingStop == false"></i>
            <i class="el-icon-video-play" v-else></i>
          </el-button>
        </span>
      </div>
    </div>
  </div>
</template>

<script>
import SparkMD5 from "spark-md5";
import { checkMd5, uploadChunk } from "@/api/tool/file";
import Bus from "@/utils/bus";

export default {
  name: "FileUpload",
  data() {
    return {
      uploadFileList: []
    }
  },

  methods: {
    //换算文件的大小单位
    formatSize(size) {
      // console.log("换算文件的大小单位" + size)
      let unit;
      let units = [" B", " K", " M", " G"];
      let pointLength = 2;
      while ((unit = units.shift()) && size > 1024) {
        size = size / 1024;
      }
      return ((unit === "B" ? size : size.toFixed(pointLength === undefined ? 2 : pointLength)) + unit);
    },

    computeMd5(file, uploadFile) {
      console.log("计算文件的md5值");
      return new Promise((resolve, reject) => {
        //分片读取并计算md5
        let time = new Date().getTime();
        let currentChunk = 0;
        let chunkSize = 5 * 1024 * 1024;
        //分片数,最少1片，最多50片
        let chunkTotal = Math.ceil(file.size / chunkSize);
        if (chunkTotal > 50) {
          chunkTotal = 50;
          chunkSize = file.size / 50;
        }

        console.log(chunkTotal);
        let fileReader = new FileReader();
        let md5 = new SparkMD5();
        const loadFile = (uploadFile) => {
          currentChunk++;
          console.log("计算第" + currentChunk + "块");
          let start = (currentChunk - 1) * chunkSize;
          let end = currentChunk * chunkSize >= file.size ? file.size : currentChunk * chunkSize;
          uploadFile.parsePercentage = parseInt((currentChunk / chunkTotal) * 100);
          let slice = file.slice(start, end);
          fileReader.readAsBinaryString(slice);
        };
        loadFile(uploadFile);

        fileReader.onload = (e) => {
          md5.appendBinary(e.target.result);
          if (currentChunk < chunkTotal) {
            loadFile(uploadFile);
          } else {
            let md5End = md5.end();
            console.log(`MD5计算完毕：${file.name} \nMD5：${md5End} \n分片：${chunkTotal} 
            \n大小:${file.size} 用时：${new Date().getTime() - time} ms`);
            // md5.end() 就是文件md5码, 如果调用2次，值会不一样
            resolve(md5End);
          }
        };
      });
    },

    //文件上传之前,el-upload自动触发
    async beforeUpload(file) {
      console.log(file)
      //单个文件的大小限制2G
      let fileSizeLimit = 2 * 1024 * 1024 * 1024;
      if (file.size > fileSizeLimit) {
        this.$message({
          showClose: true,
          message: '文件大小不能超过2G'
        });
        return 0;
      }
      let uploadFile = {};
      uploadFile.name = file.name;
      uploadFile.size = file.size;
      uploadFile.parsePercentage = 0;
      uploadFile.uploadPercentage = 0;
      uploadFile.uploadSpeed = "0 M/s";
      uploadFile.needUpload = false;
      uploadFile.chunkList = null;
      uploadFile.file = file;
      uploadFile.uploadingStop = false;
      uploadFile.md5 = "";
      this.uploadFileList.push(uploadFile);

      //async 和 await配可以实现等待异步函数计算完成
      const md5 = await this.computeMd5(file, uploadFile);
      uploadFile.md5 = md5;
      //上传服务器检查，以确认是否秒传
      console.log("md5结束");
      const { data: res } = await checkMd5(md5);
      let data = res.data;
      console.log(data);

      if (!data.isUploaded) {
        uploadFile.chunkList = data.chunkList;
        uploadFile.needUpload = true;
      } else {
        uploadFile.needUpload = false;
        uploadFile.uploadPercentage = 100;

        console.log("文件已秒传");
        ElMessage({
          showClose: true,
          message: "文件已秒传",
          type: "warning",
        });
      }
    },

    //点击暂停或开始上传
    changeUploadingStop(uploadFile) {
      console.log("点击暂停或开始上传");
      uploadFile.uploadingStop = !uploadFile.uploadingStop;
      if (!uploadFile.uploadingStop) {
        this.uploadChunk(uploadFile.file, 1, uploadFile);
      }
    },

    //上传文件,替换el-upload的action
    upload(xhrData) {
      console.log(xhrData);
      let uploadFile = null;
      // 绑定数据对象
      for (let i = 0; i < this.uploadFileList.length; i++) {
        if (
          (xhrData.file.name == this.uploadFileList[i].name) &
          (xhrData.file.size == this.uploadFileList[i].size)
        ) {
          uploadFile = this.uploadFileList[i];
          break;
        }
      }
      if (uploadFile.needUpload) {
        console.log(uploadFile);
        // 分片上传文件
        this.uploadChunk(xhrData.file, 1, uploadFile);
      }
    },

    //上传文件分片
    uploadChunk(file, index, uploadFile) {
      let chunkSize = 1024 * 1024 * 5; //10mb
      let chunkTotal = Math.ceil(file.size / chunkSize);

      if (index <= chunkTotal) {
        // 根据是否暂停，确定是否继续上传
        let startTime = new Date().getTime();
        let exit = uploadFile.chunkList.includes(index);

        if (!exit && !uploadFile.uploadingStop) {
          // 分片上传，同时计算进度条和上传速度
          // 已经上传的不在上传、上传完成后提示，上传成功
          let start = (index - 1) * chunkSize;
          let end = index * chunkSize >= file.size ? file.size : index * chunkSize;
          let sliceSize = end - start;
          let chunk = file.slice(start, end);
          //  downloadBlob(chunk,file)

          let form = {};
          form.chunkIndex = index;
          form.chunkTotal = chunkTotal;
          form.chunkSize = chunkSize;
          form.md5 = uploadFile.md5;
          form.fileSize = file.size;
          form.fileName = file.name;
          let formAndFile = new FormData();
          formAndFile.append("file", chunk);
          formAndFile.append("form", JSON.stringify(form));
          console.log("上传分片", index);

          uploadChunk(formAndFile).then((res) => {
            console.log(res);
            // 计算下载速度
            let endTime = new Date().getTime();
            let timeDif = (endTime - startTime) > 0 ? (endTime - startTime) : 1;
            let speed = 1000 * sliceSize / timeDif;
            console.log(timeDif);
            uploadFile.uploadSpeed = this.speedCalc(speed);
            uploadFile.chunkList.push(index);
            uploadFile.uploadPercentage = parseInt((uploadFile.chunkList.length / chunkTotal) * 100);

            if (index >= chunkTotal) {
              console.log("上传完毕!!!!!!");
              // Bus.$emit("reloadFileList", "upload");
              // emitter.emit("reloadFileList");
              return 0;
            }
            this.uploadChunk(file, index + 1, uploadFile);
          })
            // .catch((res) => {
            //   console.log(res);
            //   this.uploadChunk(file, index + 1, uploadFile);
            // })
            ;
        } else {
          uploadFile.uploadPercentage = parseInt((uploadFile.chunkList.length / chunkTotal) * 100);
          this.uploadChunk(file, index + 1, uploadFile);
        }
      }
    },

    // 计算下载速度
    speedCalc(speed) {
      let speedFinal = '';
      if (1024 > speed) {
        speedFinal = speed.toString + "b/s";
      } else if (1024 * 1024 >= speed && speed > 1024) {
        speedFinal = (speed / 1024).toFixed(1) + "Kb/s";
      } else if (1024 * 1024 * 1024 >= speed && speed > 1024 * 1024) {
        speedFinal = (speed / (1024 * 1024)).toFixed(1) + "Mb/s";
      } else if ((1024 * 1024 * 1024 * 1024) >= speed && speed > 1024 * 1024 * 1024) {
        speedFinal = (speed / (1024 * 1024 * 1024)).toFixed(1) + "Gb/s";
      } else if (speed > 1024 * 1024 * 1024 * 1024) {
        speedFinal = "大于1.0Tb/s";
      }
      return speedFinal;
    }
  },
}
</script>

<style  scoped>
.main {
  margin-top: 40px;
  margin-bottom: 40px;
}

.uploading {
  padding-top: 27px;
}

.progress {
  /* width: 700px; */
  display: flex;
}

.uploading .parse {
  display: flex;
}

.parse .el-progress {
  /* font-size: 18px; */
  width: 590px;
}

.progress .el-progress {
  /* font-size: 18px; */
  width: 590px;
}

.uploading .fileName {
  font-size: 17px;
  margin-right: 40px;
  margin-left: 80px;

  /* width: 80px; */
}

.uploading .fileSize {
  font-size: 17px;

  /* width: 80px; */
}

.progress .uploadSpeed {
  font-size: 17px;
  margin-left: 5px;
  padding-left: 5px;
  padding-right: 10px;
}
</style>